<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>菜鸟教程(runoob.com)</title>
</head>

<body>

    <div id="announce-contain" style="background-color:antiquewhite;width: 200px;margin: auto auto auto 100px;overflow:hidden">
        <div id="announce" style="white-space: nowrap;display:inline-block;">这里是公告这里是公告这里是公告这里是公告</div>
    </div>

    <!-- <div id="announce-contain" style="background-color:antiquewhite;width: 200px;margin: auto auto auto 100px;overflow:hidden">
        <div id="announce" style="white-space: nowrap;display:inline-block;">字比较少</div>
    </div> -->

    <!-- <div id="announce-contain" style="background-color:antiquewhite;width: 200px;white-space: nowrap;margin: auto auto auto 100px;">
        <div id="announce" style="display:inline-block;">
            <div id="announce-msg" style="display:inline-block;">比较少字的公告</div>
        </div>
    </div> -->

    <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
    <script>


        const announcer = {
            announce_contain_id: '#announce-contain',
            announce_id: '#announce',
            rest_time: 3000,
            announce_left_origin: -1,
            announce_width: -1,
            announce_contain_left: -1,
            announce_contain_right: -1,
            interval: 50, //ms
            step: 2, //px
            init: (announce_id, announce_contain_id) => {
                const me = announcer

                me.announce_contain_id = announce_contain_id
                me.announce_id = announce_id
                me.announce_left_origin = $(announce_id).offset().left
                me.announce_width = $(announce_id).width()
                me.announce_contain_left = $(announce_contain_id).offset().left
                me.announce_contain_right = me.announce_contain_left + $(announce_contain_id).width()
                me.interval = 50 //ms
                me.step = 2 //px
            },
            start: () => {
                const me = announcer
                me.roll_rest().then(me.roll_continue).then(me.start)
            },
            roll_rest: () => {
                const me = announcer
                return new Promise((resolve, reject) => {
                    setTimeout(() => {
                        console.warn('roll_rest resolved')
                        resolve()
                    }, me.rest_time)
                })
            },
            roll_continue: () => {
                const me = announcer

                const announce_left_origin = me.announce_left_origin
                const announce_width = me.announce_width
                const announce_contain_left = me.announce_contain_left
                const announce_contain_right = me.announce_contain_right

                const interval = me.interval //ms
                const step = me.step //px

                return new Promise((resolve, reject) => {

                    function walk_to(left) {
                        $('#announce').offset({ left: left })
                    }


                    function roll_appear_to_disappear() {
                        return new Promise((resolve, reject) => {
                            let announce_left = announce_left_origin

                            function is_disappear() {
                                return announce_left + announce_width < announce_contain_left
                            }


                            (function loop() {
                                setTimeout(() => {
                                    announce_left -= step;
                                    if (is_disappear()) {
                                        console.warn('roll_appear_to_disappear resolved!')
                                        resolve()
                                    } else {
                                        walk_to(announce_left)
                                        loop()
                                    }
                                }, interval)
                            }())
                        })
                    }

                    function roll_disappear_to_appear() {
                        return new Promise((resolve, reject) => {
                            let announce_left = announce_contain_right

                            function is_back_to_start() {
                                return announce_left < announce_contain_left
                            }

                            (function loop() {
                                setTimeout(() => {
                                    announce_left -= step;
                                    if (is_back_to_start()) {
                                        console.warn('roll_disappear_to_appear resolved!')
                                        resolve()
                                    } else {
                                        walk_to(announce_left)
                                        loop()
                                    }
                                }, interval)
                            }())

                        })
                    }

                    roll_appear_to_disappear().then(roll_disappear_to_appear).then(resolve)
                })
            }
        }

        $(document).ready(function () {
            announcer.init('#announce', '#announce-contain')
            announcer.start()
        })
    </script>
</body>

</html>